Identify

In this lab, we will print our own text in Wesnoth. To accomplish this task, we will first locate a section of code responsible for printing text. Then, we will use a code cave to modify the game's memory to display our text.

Understand

There are multiple approaches to print our own text inside a game:

  1. Use an external overlay.
  2. Create a code cave inside the game's main display loop and call the function responsible for displaying text.
  3. Create a code cave inside a function responsible for displaying text and modify the text about to be displayed.

For this lab, we will use the third approach as it is the easiest to do in Wesnoth. We will examine the other approaches more in-depth in future labs. Different games are suited best to different methods.

Locating Text

Our first task is to locate the game's code responsible for displaying text. To start, we need to find a string of letters that appears in the game. For Wesnoth, we can use the "Terrain Description" text that is displayed when clicking on a tile. Any description will work, but for this lab, we will use the description for the "Ford" tile. For other games, chat messages are a good starting location.

First, select a map that has "Ford" tiles on it. "Den of Onis" is one example:

Map with ford tiles on it

When the map loads, select a "Ford" tile and select the "Terrain Description" entry on the context-menu:

Terrain description on a ford tile

This will bring up the description for the tile, which contains a long string of text:

Terrain description on a ford tile

We can use Cheat Engine to search for where this text is stored within the game. Make sure to close down the description box before searching to reduce the amount of results. Due to the unique nature of the text, we only need to search for a couple words:

Searching for text in Cheat Engine

To narrow down which address represents the string we are interested in, change the first letter of every string. The version that displays when you go back into Wesnoth and select the description represents your address. In this case, the string starting with "Lhen" was displayed, making our address 0x10CE996B.

Determining string address in Cheat Engine

Locating PrintText

We can now use the address we found to locate the function responsible for printing text. We know that the print text function must access this text in some way to print it. To determine where this function is, we can set a breakpoint on a byte of the text.

Breakpoint on text byte

With the breakpoint set, go back into Wesnoth and invoke the "Terrain Description" action again. Your breakpoint will pop immediately:

Breakpoint on text byte

Examining this code, we appear to be in a loop responsible for moving each byte of the text into a buffer. Like we did in previous labs, we want to navigate to the code that called this lower-level code by using execute until return and stepping out.

Breakpoint on text byte

This call looks like it could be responsible for populating the terrain description box with text. If we continue execution, we notice that this code is called multiple times for each section of the description box. To determine the parameters passed to this call, we can set a breakpoint on 0x005ED114 and invoke the "Terrain Description" action again:

Breakpoint on text byte

It appears that the text is loaded into the register "edx" and then that value is moved to the location pointed at by "esp". This is identical to pushing the value of "edx" on the top of the stack. While we have not discussed the stack yet, for the purpose of this lab, we need to know that often functions will retrieve values off of the stack for use in execution.

Memory and Endianness

One thing you may have noticed is that the address in "edx" does not match the address we found in Cheat Engine. Since the text space is dynamically allocated, we will need to understand how to retrieve the value of the text from "edx" to create our code cave.

Invoke the "Terrain Description" action again to force our breakpoint to pop. Once it does, right-click on the value of "edx" and choose "Follow in Dump":

Follow in dump action

This will change the current address displaying in the dump to the value of "edx". As we discussed in previous labs, the dump section displays the current running memory of a process. It's important to remember that both the dump section and Cheat Engine are displaying and searching the same data.

Dump section

This value stored in "edx" is obviously not a text string. However, if we examine the value of the bytes, we see that they share many similarities to the address we found in Cheat Engine. In the previous lab, we briefly discussed a concept known as endianness. Most Windows-based CPUs are little endian. By definition, this means that the least-significant byte is stored in the smallest address.

In practice, this means that when the address 0x12345678 is stored in memory, it will be stored as "78 56 34 12". In this case, 78 represents the least-significant byte, or the smallest value. A good comparison is to imagine the number 123. Expressed in a longer form, this value can be understood as 1*100 + 2*10 + 3*1. The smallest value in this form is the number 3.

The second part of this definition can be understood by examining the dump. In the dump, memory addresses grow from a lower-value to a higher-value. Because of this, the least-significant byte will be stored "first" in memory. The combination of these factors make addresses stored in memory appear "reversed".

Now that we understand endianness, we can understand that the value stored at "edx" is an address. We can quickly navigate to this address in the dump by selecting all the bytes and selecting "Follow in Dump" again:

Dump section

After selecting this, we arrive at our string's location in memory:

Dump section

To reference this value in assembly, we can make use of the "ptr ds" keyword:

  mov eax, dword ptr ds:[edx]

This will load the value of the address stored in "edx" into "eax". In this case, it would load the value 0x10CE9968 into eax. We could then use the "ptr ds" keyword again to access the individual bytes of the text.

Changing Text

With this reversing done, we can start creating our hack. To verify that we have the correct method, we will create a code cave that will change the text displayed each time the "Terrain Description" action is invoked. To do this simply, we will increase the value of the first byte each time our code cave is executed. This will change the value of the character and allow us to verify that our hack is working.

Since we know the call at 0x005ED129 is responsible for printing the text and is also 5 bytes long, we will use it as our redirection point. Like in previous code cave labs, any location near the end of program's memory will work for our cave location. In this case we will create it at 0x01343E1B. As usual, we will replace the hooking location with a jump to our code cave:

Redirection

In our code cave, we will first save the registers. Then we will use the "ptr ds" keyword to load the value of the text from edx into eax. After that, we will use the "inc" operator to increase the value of the first byte of the string. For example, if the first byte is currently "A" (ASCII value 65) it will be increased to "B" (ASCII value 66). Finally, we will restore the registers, recreate the call, and then jump back to the original code.

Redirection

With this completed, go back into Wesnoth and invoke the "Terrain Description" action multiple times. You will notice a character after the image changes each time, demonstrating that we have successfully modified the text displayed.

Changed Text

Next Steps

In our next lab, we will use our ability to print text to create a stathack, a type of hack that allows us to view other players' statistics.